{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Defining vector spaces"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "1. Adding vectors in any order shouldn’t matter: v + w = w + v for any vectors v and w.\n",
    "2. Adding vectors in any grouping shouldn’t matter: u + (v + w) should be the same as (u + v) + w, meaning that a statement like u + v + w should be unambiguous.\n",
    "3. Multiplying vectors by several scalars should be the same as multiplying by all the scalars at once. If a and b are scalars and v is a vector, then a · (b · v) should be the same as (a · b) · v.\n",
    "4. Multiplying a vector by 1 should leave it unchanged: 1 · v = v.\n",
    "5. Addition of scalars should be compatible with scalar multiplication: a · v + b · v should be the same as (a + b) · v.\n",
    "6. Addition of vectors should also be compatible with scalar multiplication: a · (v + w) should be the same as a · v + a · w."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Exercises \n",
    "\n",
    "Implement vector2 and vector3 class"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "from abc import ABCMeta, abstractmethod"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [],
   "source": [
    "class Vector(metaclass=ABCMeta):\n",
    "    @abstractmethod\n",
    "    def scale(self, scalar):\n",
    "        pass\n",
    "    @abstractmethod\n",
    "    def add(self, other):\n",
    "        pass\n",
    "    def __mul__(self, scalar):\n",
    "        return self.scale(scalar)\n",
    "    def __rmul__(self, scalar):\n",
    "        return self.scale(scalar)\n",
    "    def __add__(self, other):\n",
    "        return self.add(other)\n",
    "    def subtract(self, other):\n",
    "        return self.add(-1 * other)\n",
    "    def __sub__(self, other):\n",
    "        return self.subtract(other)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The abc module contains helper classes, functions, and method decorators that help\n",
    "define an abstract base class, a class that is not intended to be instantiated. Instead, it’s designed to be used as a template for classes that inherit from it. The @abstract-\n",
    "method decorator means that a method is not implemented in the base class and\n",
    "needs to be implemented for any child class. \n",
    "\n",
    "For instance, if you try to instantiate a\n",
    "vector with code like v = Vector() , you get the following TypeError :\n",
    "TypeError: Can't instantiate abstract class Vector with abstract methods add,\n",
    "scale"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [],
   "source": [
    "class Vec2(Vector):\n",
    "    def __init__(self, x, y):\n",
    "        self.x = x\n",
    "        self.y = y\n",
    "    def add(self, other):\n",
    "        return Vec2(self.x + other.x, self.y + other.y)\n",
    "    def scale(self, scalar):\n",
    "        return Vec2(scalar*self.x, scalar*self.y)\n",
    "    def __eq__(self, other):\n",
    "        return self.x == other.x and self.y == other.y\n",
    "    def __repr__(self):\n",
    "        return \"Vec2({},{})\".format(self.x, self.y)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Vector3 can be implemented as the same way"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# math.isclose"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [],
   "source": [
    "import math"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "False"
      ]
     },
     "execution_count": 10,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "math.isclose(2,1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "True"
      ]
     },
     "execution_count": 13,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "math.isclose(2.000000001, 2)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.8.5"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
